from aliyunsdkcore.client import AcsClient
from flask import Flask, redirect, url_for, jsonify, session, Response
from flask import render_template
from flask import request, flash
from werkzeug.utils import secure_filename
from openai import OpenAI
import util
import random, time
import os
import cv2
import numpy as np
from pathlib import Path
import sys
from aliyunsdkcore.request import CommonRequest
from flask_socketio import SocketIO
import threading
import queue

# 添加项目根目录到Python路径
PROJECT_ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(PROJECT_ROOT))

# 导入模型和处理函数
from function.model_loader import load_models
import function.image_processor as image_processor

app = Flask(__name__)
app.secret_key = 'a_very_secret_key_123456!@#$%^&*()'
socketio = SocketIO(app)

# 初始化模型变量
seg_model = None
emotion_model = None

def get_models():
    global seg_model, emotion_model
    if seg_model is None or emotion_model is None:
        print("正在加载模型...")
        seg_model, emotion_model = load_models()
        print("模型加载完成！")
    return seg_model, emotion_model

# 你需要填写以下阿里云短信参数
ALIYUN_ACCESS_KEY_ID = 'LTAI5tNYRWu1SB6fSAixsSyE'
ALIYUN_ACCESS_KEY_SECRET = 'CT46EJgSesfQvuXI2x7FQPKe0hVK08'
ALIYUN_SIGN_NAME = '阿里云短信测试'
ALIYUN_TEMPLATE_CODE = 'SMS_154950909'

client = AcsClient(ALIYUN_ACCESS_KEY_ID, ALIYUN_ACCESS_KEY_SECRET, 'cn-hangzhou')

# 初始化 OpenAI 客户端（火山方舟 Ark）
client = OpenAI(
    base_url="https://ark.cn-beijing.volces.com/api/v3",
    api_key="3e21bdde-92cc-4442-b7c4-88fa18903b42"  # 替换为你的真实 API Key
)

# 用于保存对话历史（简单实现，生产环境建议用 session 或数据库）
messages = [
    {"role": "system", "content": "你是一个智能助手，帮助用户解答问题。"}
]

@app.route("/chat", methods=["POST"])
def chat():
    user_input = request.json.get("message")
    if not user_input:
        return jsonify({"reply": "请输入内容"}), 400

    messages.append({"role": "user", "content": user_input})

    # 非流式返回
    completion = client.chat.completions.create(
        model="ep-20250707110146-s7blv",
        messages=messages,
    )
    reply = completion.choices[0].message.content
    messages.append({"role": "assistant", "content": reply})

    return jsonify({"reply": reply})

UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), 'static', 'uploads')
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'bmp'}  # 移除视频格式

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/')
def hello_world():  # put application's code here
    success = request.args.get('success')
    return render_template('index.html', success=success)

@app.route('/login', methods=['get','post'])
def login():
    # 获取客户提交的用户名和密码
    success = request.args.get('success') 
    username = request.values.get('username')
    password = request.values.get('password')
    # 和数据库user表的数据进行匹配， 验证用户名和密码
    users = util.find_all()
    for user in users:
        if username == user[1] and password == user[2]:
            # 跳转页面
            return render_template('detect.html')
    # 用户名或密码错误，返回登录页并提示
    error = None
    if username or password:
        error = "用户名或密码错误"
    return render_template('index.html', success=success, error=error)

@app.route('/reload', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form.get('username')
        phone = request.form.get('phone')
        sms_code = request.form.get('sms_code')
        password = request.form.get('password')
        confirm_password = request.form.get('confirm_password')

        # 验证两次密码是否一致
        if password != confirm_password:
            return render_template('reload.html', error="两次密码输入不一致，请重新注册")

        # 校验必填项
        if not username or not phone or not password or not sms_code:
            return render_template('reload.html', error="所有项均不能为空")

        # 校验短信验证码
        if sms_code != session.get('sms_code') or phone != session.get('sms_phone'):
            return render_template('reload.html', error="短信验证码错误")

        # 检查用户名是否存在
        users = util.find_all()
        for user in users:
            if username == user[1]:
                return render_template('reload.html', error="用户名已存在，请更换用户名")
            if phone == getattr(user, 'phone', None):
                return render_template('reload.html', error="手机号已注册")

        # 插入数据库
        try:
            util.insert_user_with_phone(username, password, phone)
            return redirect(url_for('hello_world', success='注册成功，请登录'))
        except Exception as e:
            import traceback
            traceback.print_exc()
            return render_template('reload.html', error=f"注册失败: {str(e)}")

    return render_template('reload.html')

@app.route('/check_username')
def check_username():
    username = request.args.get('username')
    users = util.find_all()
    exists = any(user[1] == username for user in users)
    return jsonify({'exists': exists})

@app.route('/send_sms_code')
def send_sms_code():
    phone = request.args.get('phone')
    if not phone:
        return jsonify({'success': False, 'msg': '手机号不能为空'})
    code = str(random.randint(100000, 999999))
    request_ = CommonRequest()
    request_.set_domain('dysmsapi.aliyuncs.com')
    request_.set_method('POST')
    request_.set_protocol_type('https')
    request_.set_version('2017-05-25')
    request_.set_action_name('SendSms')
    request_.add_query_param('PhoneNumbers', phone)
    request_.add_query_param('SignName', ALIYUN_SIGN_NAME)
    request_.add_query_param('TemplateCode', ALIYUN_TEMPLATE_CODE)
    request_.add_query_param('TemplateParam', '{"code":"%s"}' % code)
    try:
        response = client.do_action_with_exception(request_)
        session['sms_code'] = code
        session['sms_code_time'] = int(time.time())
        session['sms_phone'] = phone
        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'success': False, 'msg': str(e)})

@app.route('/reset_password', methods=['GET', 'POST'])
def reset_password():
    if request.method == 'GET':
        return render_template('reset_password.html')
    phone = request.form.get('phone')
    sms_code = request.form.get('sms_code')
    new_password = request.form.get('new_password')
    confirm_new_password = request.form.get('confirm_new_password')

    # 校验必填项
    if not phone or not sms_code or not new_password or not confirm_new_password:
        return render_template('reset_password.html', error='所有项均不能为空')
    if new_password != confirm_new_password:
        return render_template('reset_password.html', error='两次新密码输入不一致')
    if sms_code != session.get('sms_code') or phone != session.get('sms_phone'):
        return render_template('reset_password.html', error='短信验证码错误')

    # 查找用户并重置密码
    users = util.find_all()
    user_id = None
    for user in users:
        if len(user) > 3 and user[3] == phone:
            user_id = user[0]
            break
    if not user_id:
        return render_template('reset_password.html', error='手机号未注册')
    try:
        util.update_password_by_id(user_id, new_password)
        return render_template('reset_password.html', success='密码重置成功，请登录')
    except Exception as e:
        import traceback
        traceback.print_exc()
        return render_template('reset_password.html', error=f'密码重置失败: {str(e)}')

@app.route('/check_phone')
def check_phone():
    phone = request.args.get('phone')
    users = util.find_all()
    exists = any((len(user) > 3 and user[3] == phone) for user in users)
    return jsonify({'exists': exists})

@app.route('/detect/upload', methods=['GET', 'POST'])
def detect_upload():
    if request.method == 'POST':
        print("开始处理上传请求...")  # 调试信息
        if 'file' not in request.files:
            flash('没有文件部分')
            return render_template('upload.html', error='没有文件部分')
        files = request.files.getlist('file')
        if not files or all(f.filename == '' for f in files):
            flash('未选择文件')
            return render_template('upload.html', error='未选择文件')
        
        results = []
        
        # 获取模型
        seg_model, emotion_model = get_models()
        
        for index, file in enumerate(files):
            if file and allowed_file(file.filename):
                # 生成带时间戳的唯一文件名
                timestamp = int(time.time() * 1000)
                original_filename = secure_filename(file.filename)
                filename = f"{timestamp}_{index}_{original_filename}"
                save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
                file.save(save_path)
                print(f"保存文件: {filename}")  # 调试信息
                
                try:
                    # 使用图像处理函数处理图片
                    processed_image, id_emotions = image_processor.process_image(save_path, seg_model, emotion_model)
                    print(f"处理结果: {id_emotions}")  # 调试信息
                    
                    if processed_image is not None:
                        # 保存处理后的图片，使用唯一的文件名
                        processed_filename = f'processed_{timestamp}_{index}_{original_filename}'
                        processed_path = os.path.join(app.config['UPLOAD_FOLDER'], processed_filename)
                        cv2.imwrite(processed_path, processed_image)
                        print(f"保存处理后的图片: {processed_filename}")  # 调试信息
                        
                        # 如果检测到情绪，添加到结果中
                        if id_emotions:
                            for face_id, emotion in id_emotions.items():
                                results.append({
                                    'filename': processed_filename,  # 使用处理后的图片
                                    'face_id': face_id,
                                    'emotion': emotion
                                })
                        else:
                            results.append({
                                'filename': processed_filename,
                                'face_id': None,
                                'emotion': '未检测到人脸'
                            })
                    else:
                        results.append({
                            'filename': filename,
                            'face_id': None,
                            'emotion': '处理失败'
                        })
                    
                except Exception as e:
                    print(f"处理出错: {str(e)}")  # 调试信息
                    results.append({
                        'filename': filename,
                        'face_id': None,
                        'emotion': f'处理失败: {str(e)}'
                    })
                
                # 清理原始上传文件
                try:
                    os.remove(save_path)
                except:
                    pass
            else:
                results.append({
                    'filename': file.filename,
                    'face_id': None,
                    'emotion': '文件类型不支持'
                })
        
        print(f"处理结果: {results}")  # 调试信息
        
        # 存入session
        session['upload_results'] = results
        print("准备重定向到结果页面...")  # 调试信息
        return redirect(url_for('detect_upload_result'))
    return render_template('upload.html')

@app.route('/detect/upload_result')
def detect_upload_result():
    print("进入结果页面...")  # 调试信息
    results = session.get('upload_results')
    print(f"从session获取结果: {results}")  # 调试信息
    
    # 清理session，防止刷新重复显示
    session.pop('upload_results', None)
    
    # 只要有results就显示结果页面
    if not results:
        print("没有找到结果，重定向回上传页面")  # 调试信息
        return redirect(url_for('detect_upload'))
    return render_template('upload_result.html', results=results)

@app.route('/detect/camera', methods=['GET', 'POST'])
def detect_camera():
    return render_template('camera.html')

@app.route('/detect/camera_upload', methods=['POST'])
def detect_camera_upload():
    file = request.files.get('file')
    if file and allowed_file(file.filename):
        try:
            filename = secure_filename('camera_' + file.filename)
            save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            file.save(save_path)
            
            # 获取模型
            seg_model, emotion_model = get_models()
            
            # 使用图像处理函数处理图片
            processed_image, id_emotions = image_processor.process_image(save_path, seg_model, emotion_model)
            print(f"摄像头上传处理结果 - id_emotions: {id_emotions}")  # 调试信息
            
            # 获取检测到的情绪
            results = []
            print(f"id_emotions类型: {type(id_emotions)}")  # 调试信息
            print(f"id_emotions内容: {id_emotions}")  # 调试信息
            
            if isinstance(id_emotions, dict) and 'error' not in id_emotions:
                print("开始处理情绪结果...")  # 调试信息
                for face_id, emotion in id_emotions.items():
                    print(f"处理人脸 {face_id} 的情绪: {emotion}")  # 调试信息
                    if emotion != '未检测到人脸':  # 跳过未检测到人脸的情况
                        results.append({
                            'face_id': face_id,
                            'emotion': emotion
                        })
            
            # 保存带框图片，确保使用正确的编码
            result_filename = 'camera_result.jpg'
            result_path = os.path.join(app.config['UPLOAD_FOLDER'], result_filename)
            if processed_image is not None:
                # 确保图片是BGR格式（OpenCV默认格式）
                if len(processed_image.shape) == 3 and processed_image.shape[2] == 3:
                    # 设置JPEG压缩参数
                    encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
                    success, encoded_img = cv2.imencode('.jpg', processed_image, encode_param)
                    if success:
                        # 将编码后的图片写入文件
                        with open(result_path, 'wb') as f:
                            f.write(encoded_img.tobytes())
                        image_url = '/static/uploads/' + result_filename
                    else:
                        image_url = None
                else:
                    image_url = None
            else:
                image_url = None

            # 删除原始上传图片
            if os.path.exists(save_path):
                os.remove(save_path)
            
            if results:
                return {
                    'success': True,
                    'result': results,
                    'image_url': image_url
                }
            else:
                return {
                    'success': True,
                    'result': [],
                    'image_url': image_url
                }
        except Exception as e:
            print(f"处理出错: {str(e)}")  # 添加错误日志
            # 确保清理临时文件
            if os.path.exists(save_path):
                os.remove(save_path)
            return {'success': False, 'msg': f'处理失败: {str(e)}'}
    return {'success': False, 'msg': '文件类型不支持'}

if __name__ == '__main__':
    socketio.run(app, debug=True, allow_unsafe_werkzeug=True)
